package com.acheli.rideable.functionLathes;

import com.acheli.registry.config.CustomDataBus;
import com.acheli.registry.network.ACHMessages;
import com.acheli.registry.network.ACHeliPacketType;
import com.acheli.registry.network.packet.CustomSyncableC2SPacket;
import com.acheli.registry.resource.DynamicResourcePack;
import com.acheli.rideable.entites.RideableEntity;
import com.acheli.rideable.functionLathes.component.compile.JSUtils;
import com.acheli.rideable.model.AbstractComponent;
import com.acheli.rideable.entites.ComponentEntity;
import com.acheli.utils.rotate.EntityDirectionUtils;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.event.InputEvent;
import org.joml.Quaternionf;
import org.mozilla.javascript.*;

import java.nio.file.Files;
import java.util.HashMap;
import java.util.Objects;

import static com.acheli.ACHeli.MODID;

public abstract class ComponentFL extends RotateAbleEntityFL implements AbstractComponent {
    private double mass = 0;
    private double revolutionSpeed = 0;
    private NativeObject jsObj = new NativeObject();

    public static class CData{
        public String ID = "";
        public double[] relativePosition = {0, 0, 0};
        public double[] relativeBoxLength = {1, 1, 1};
    }

    public static float getOrientAngle(Orientation orientation) {
        float orientAngle = 0;
        switch (orientation) {

            case North -> {
            }
            case South -> {
                orientAngle = 180;
            }
            case West -> {
                orientAngle = -90;
            }
            case East -> {
                orientAngle = 90;
            }
        }
        return orientAngle;
    }

    @Override
    public void setMass(double mass) {
        this.mass = mass;
    }
    @Override
    public double getMass() {
        return mass;
    }

    public CompoundTag clientSending(ACHeliPacketType packetType){
        return new CompoundTag();
    }

    public CompoundTag serverReceiveAndSending(CompoundTag serverOriginNbt, ServerPlayer executingPlayer, ACHeliPacketType packetType) {

        return null;
    }

    @Override
    public void setRevolutionSpeed(double revolutionSpeed) {
        this.revolutionSpeed = revolutionSpeed;
    }

    @Override
    public double getRevolutionSpeed() {
        return revolutionSpeed;
    }

    public  void onGround(boolean v){

    }

    public void interact(Player player, InteractionHand hand) {
    }

    public void setJS(NativeObject js) {
        jsObj = js;
    }
    public NativeObject getJS() {
        return jsObj;
    }



    public  enum Orientation {
        North,
        South,
        West,
        East,
    }

    public final String ID;

    protected boolean enableVelocity = false;
    private Vec3 velocity = Vec3.ZERO;

    private Vec3 lastPos;

    private Vec3 relativePosition = Vec3.ZERO;
    private Vec3 relativeAABB_Position = Vec3.ZERO; //碰撞箱相对坐标
    private double relativeAABB_X_Length = 1f; //碰撞箱相对x边长
    private double relativeAABB_Y_Length = 1f; //碰撞箱相对y边长
    private double relativeAABB_Z_Length = 1f; //碰撞箱相对z边长
    protected RideableEntity vehicle;

    public Orientation orientation = Orientation.North;

    private ComponentEntity body;

    public ComponentFL(String ID, RideableEntity vehicle, Vec3 relativePosition){
        this.ID = ID;
        this.vehicle = vehicle;
        setRelativePosition(relativePosition);
    }

    public ComponentFL(String ID, RideableEntity vehicle, Vec3 relativePosition, Vec3 relativeBoxLength) {
        this.ID = ID;
        this.vehicle = vehicle;
        setRelativePosition(relativePosition);
        setRelativeAABB(relativeBoxLength.x, relativeBoxLength.y, relativeBoxLength.z);
    }

//    public ComponentFL(String ID, RideableEntity vehicle, Vec3 relativePosition, Vec3 relativeBoxPosition, double relativeBoxXLength, double relativeBoxYLength, double relativeBoxZLength) {
//        this.ID = ID;
//        this.vehicle = vehicle;
//        setRelativePosition(relativePosition);
//        setRelativeAABB(relativeBoxPosition, relativeBoxXLength, relativeBoxYLength, relativeBoxZLength);
//    }

    public void setRelativeAABB(double relativeAABBXLength, double relativeAABBYLength, double relativeAABBZLength ) {
        this.relativeAABB_X_Length = relativeAABBXLength;
        this.relativeAABB_Y_Length = relativeAABBYLength;
        this.relativeAABB_Z_Length = relativeAABBZLength;
    }
//    public void setRelativeAABB(Vec3 relativeAABBPosition, double relativeAABBXLength, double relativeAABBYLength, double relativeAABBZLength ) {
//        this.relativeAABB_Position = relativeAABBPosition;
//        this.relativeAABB_X_Length = relativeAABBXLength;
//        this.relativeAABB_Y_Length = relativeAABBYLength;
//        this.relativeAABB_Z_Length = relativeAABBZLength;
//    }

    public Vec3 getRelativeAABB_Position() {
        return relativeAABB_Position;
    }

    public double getRelativeAABB_X_Length() {
        return relativeAABB_X_Length;
    }

    public double getRelativeAABB_Y_Length() {
        return relativeAABB_Y_Length;
    }

    public double getRelativeAABB_Z_Length() {
        return relativeAABB_Z_Length;
    }

    public AABB getVisibilityBoundingAABB(AABB box) {
        return AABB.ofSize(box.getCenter().add(relativeAABB_Position), box.getXsize() * relativeAABB_X_Length, box.getYsize() * relativeAABB_Y_Length, box.getZsize() * relativeAABB_Z_Length);
    }
    public ComponentEntity getBody() {
        return body;
    }
    public void setBody(ComponentEntity body) {
        this.body = body;
    }

    @Override
    public void tick() {
        if (getBody().level().isClientSide) {
            ACHMessages.sendToServer(new CustomSyncableC2SPacket(
                    getBody().getId(), getBody().getUUID(), clientSending(ACHeliPacketType.ComponentActive), ACHeliPacketType.ComponentActive));
        }
    }
    @Override
    public void bodyTick(ComponentEntity dynamicBody) {

    }

    @Override
    public void renderTick(ComponentEntity dynamicBody, PoseStack matrices, float tickDelta) {
        Quaternionf target = totalRotation;
        target.rotateY((float) totalYMomentum);
        target.rotateX((float) totalXMomentum);
        target.rotateZ((float) totalZMomentum);
        totalRotation.slerp(target, 0.1f * tickDelta);
        totalYMomentum *=  0.998;
        totalXMomentum *=  0.998;
        totalZMomentum *=  0.998;

        if (enableVelocity) {
            Vec3 nowPos = dynamicBody.position();
            if (lastPos != null) {
                velocity = EntityDirectionUtils.getDirectionVector(lastPos, nowPos);
            }
            lastPos = nowPos;
        }

    }

    @Override
    public void setRelativePosition(Vec3 pos) {
        relativePosition = pos;
    }

    @Override
    public Vec3 getRelativePosition() {
        return relativePosition;
    }

    @Override
    public Vec3 getPos(double x, double y, double z) {
        return new Vec3(x + relativePosition.x(),
                y+ relativePosition.y(),
                z+ relativePosition.z());
    }
    @Override
    public Vec3 getPos(Vec3 inputPos) {
        return new Vec3(inputPos.x + relativePosition.x(),
                inputPos.y+ relativePosition.y(),
                inputPos.z+ relativePosition.z());
    }
    @Override
    public Vec3 getPos() {
        Vec3 originPos = vehicle.position();
        return new Vec3(originPos.x()+ relativePosition.x(),
                originPos.y()+ relativePosition.y(),
                originPos.z()+ relativePosition.z());
//        return originPos;
    }

    public Vec3 getVelocity() {
        return velocity;
    }

    public void setVehicle(RideableEntity vehicle) {
        this.vehicle = vehicle;
    }
    public RideableEntity getVehicle() {
        return this.vehicle;
    }
}
